home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Fonts / installfont / unadobe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-01  |  9.4 KB  |  345 lines

  1. /*
  2. ** U N A D O B E
  3. **
  4. ** Extract font PostScript code from a Macintosh font file resource fork
  5. ** (a procedure somewhat akin to extracting water out of rocks), basically
  6. ** the same function as the oldie unAdobe program on the Macintosh.
  7. ** In addition to this it does the job of the unfont (or pfbtopfa)
  8. ** program, that is, reads PC pfb format packed font files.
  9. **
  10. ** Information used in this program was acquired from:
  11. ** - Inside Macintosh I p.128: Format of a Resource File
  12. ** - Adobe TechNote #5040: Supporting Downloadable PostScript Language Fonts
  13. **
  14. ** BUGS: this code is specifically written for Motorola-endian machines (like
  15. ** Macintosh resource files also are); there is no provision for reading
  16. ** MacBinary-encoded Macintosh files (solution: get rid of 128 first bytes,
  17. ** for example with "dd", then feed file on stdin).
  18. **
  19. ** A million thanks to Rob Elliott <relliott@b11.b11.ingr.com> for pointing
  20. ** me in the correct direction on where to find the unpacking information and
  21. ** Mark Adler <madler@cco.caltech.edu> for telling me about the NeXT method
  22. ** of making the Macintosh file system resource fork available as .#rsrc#
  23. **
  24. ** Written by Otto J. Makela <otto@jyu.fi>
  25. ** Distributed under the GNU Public Licence -- see file COPYING for details
  26. */
  27.  
  28. #include    <stdio.h>
  29. #include    <stdlib.h>
  30. #include    <string.h>
  31.  
  32. int verbose=0;
  33.  
  34. main(int argc, char *argv[])    {
  35.   int loop,i,files=0,type=0;
  36.   FILE *fi,*fo;
  37.  
  38.   /* Loop thru all files given on command line */
  39.  loop:
  40.   for(loop=1; loop<argc; loop++)    {
  41.     /* Possible argument */
  42.     if(*argv[loop]=='-')
  43.       if(argv[loop][1])    {
  44.     while(i=*++argv[loop])
  45.       switch(i)    {
  46.       case 'm': type=1; break;
  47.       case 'p': type=2; break;
  48.       case 'v': verbose++; break;
  49.       default: goto usage;
  50.       }
  51.     continue;
  52.       } else    {
  53.     /* Bare dashes mean stdin/out */
  54.     fi=stdin;
  55.     fo=stdout;
  56.       }
  57.     else if(!(fi=fopen(argv[loop],"rb")))    {
  58.       fprintf(stderr,"%s: can't open file \"%s\" for input\n",
  59.           *argv,argv[loop]);
  60.       exit(1);
  61.     } else    {
  62.       char *p,filename[BUFSIZ];
  63.  
  64.       strcpy(filename,argv[loop]);
  65.       /* On a NeXT you see Macintosh resource forks as .#rsrc# files */
  66.       if(p=strstr(filename,".#rsrc#"))    {
  67.     *p='\0';
  68.     if(!type) type=1;
  69.       } else if(p=strstr(filename,".pfb"))    {
  70.     p[3]='a';
  71.     if(!type) type=2;
  72.       } else
  73.     strcat(filename,".ps");
  74.  
  75.       if(!(fo=fopen(filename,"wt")))    {
  76.     fprintf(stderr,"%s: can't open file \"%s\" for output\n",
  77.         *argv,filename);
  78.     exit(1);
  79.       }
  80.     }
  81.  
  82.     if(type==1)    {
  83.       if(verbose) fprintf(stderr,"Macintosh resource file %s:\n",argv[loop]);
  84.       if(macfont(fi,fo))    {
  85.     fprintf(stderr,"%s: EOF or data format errors reading file \"%s\"\n",
  86.         *argv,argv[loop]);
  87.     exit(1);
  88.       }
  89.     } else if(type==2)    {
  90.       if(verbose) fprintf(stderr,"PC pfb file %s:\n",argv[loop]);
  91.       if(pcfont(fi,fo))    {
  92.     fprintf(stderr,"%s: EOF or data format errors reading file \"%s\"\n",
  93.         *argv,argv[loop]);
  94.     exit(1);
  95.       }
  96.     } else    {
  97.       fprintf(stderr,"%s: could not determine file \"%s\" type\n",
  98.           *argv,argv[loop]);
  99.     usage:
  100.       fprintf(stderr,"usage: %s [-mpv] fontfile...\n"
  101.           "where the font file type is guessed from file extension or:\n"
  102.           "-m\tSet Macintosh resource file format for next file\n"
  103.           "-p\tSet PC pfb file format for next file\n"
  104.           "-v\tIncrease verboseness (repeat for more)\n",*argv);
  105.       exit(1);
  106.     }
  107.  
  108.     if(fi!=stdin) fclose(fi);
  109.     if(fo!=stdout) fclose(fo);
  110.     type=0; files++;
  111.   }
  112.  
  113.   /* If no arguments given, read stdin and output to stdout */
  114.   if(!files)    {
  115.     argv[1]="-";
  116.     argc=2;
  117.     goto loop;
  118.   }
  119.  
  120.   exit(0);
  121. }
  122.  
  123.  
  124. /*
  125. ** Read a Macintosh resource fork file
  126. */
  127. macfont(FILE *fi,FILE *fo)    {
  128.   int i;
  129.  
  130.   /* The following data represents a Macintosh resource fork structure */
  131.   struct    {
  132.     unsigned long int data_offset;
  133.     unsigned long int map_offset;
  134.     unsigned long int data_length;
  135.     unsigned long int map_length;
  136.   } resourceheader;
  137.   struct    {
  138.     unsigned char dummy0[16];
  139.     unsigned long int dummy1;
  140.     unsigned short int dummy2;
  141.     unsigned short int resourcefile_attribute;
  142.     unsigned short int typelist_offset;
  143.     unsigned short int namelist_offset;
  144.   } resourcemap;
  145.   unsigned short type_count;
  146.   struct    {
  147.     char resource_type[4];
  148.     unsigned short int reference_count;
  149.     unsigned short int referencelist_offset;
  150.   } typelist;
  151.   struct    {
  152.     unsigned short int resource_id;
  153.     unsigned short int referencelist_offset;
  154.     union    {
  155.       unsigned char resource_attribute;
  156.       unsigned long data_offset;
  157.     } reference;
  158.     unsigned long int dummy3;
  159.   } referencelist;
  160.  
  161.  
  162.   /* First read main resource file header */
  163.   if(fread(&resourceheader,1,sizeof(resourceheader),fi)!=
  164.      sizeof(resourceheader))
  165.     return(1);
  166.   
  167.   if(verbose) fprintf(stderr,
  168.               "resource data\toffset = %lu\n"
  169.               "\t\tlength = %lu\n"
  170.               "resource map\toffset = %lu\n"
  171.               "\t\tlength = %lu\n",
  172.               resourceheader.data_offset,resourceheader.data_length,
  173.               resourceheader.map_offset,resourceheader.map_length);
  174.  
  175.   fseek(fi,resourceheader.map_offset,0);
  176.   if(fread(&resourcemap,1,sizeof(resourcemap),fi)!=sizeof(resourcemap))
  177.     return(1);
  178.  
  179.   if(verbose) fprintf(stderr,
  180.               "resourcefile attribute = %04x\n"
  181.               "type list offset = %lu (absolute %lu)\n"
  182.               "name list offset = %lu (absolute %lu)\n",
  183.               resourcemap.resourcefile_attribute,
  184.               resourcemap.typelist_offset,
  185.               resourceheader.map_offset+resourcemap.typelist_offset,
  186.               resourcemap.namelist_offset,
  187.               resourceheader.map_offset+resourcemap.namelist_offset);
  188.  
  189.   fseek(fi,resourceheader.map_offset+resourcemap.typelist_offset,0);
  190.   if(fread(&type_count,1,sizeof(type_count),fi)!=sizeof(type_count))
  191.     return(1);
  192.  
  193.   /* Search for a POST resource containing the PostScript code */
  194.   for(i=0; i<=type_count; i++)    {
  195.     if(fread(&typelist,1,sizeof(typelist),fi)!=sizeof(typelist))
  196.       return(1);
  197.     if(verbose)
  198.       fprintf(stderr,"resource_type=\"%.4s\"\n",typelist.resource_type);
  199.     if(!strncmp(typelist.resource_type,"POST",4)) break;
  200.   }
  201.  
  202.   /* No POST resource was found */
  203.   if(i>type_count) return(1);
  204.  
  205.   if(verbose) fprintf(stderr,
  206.               "%.4s resources = %u\n"
  207.               "%.4s reference list offset = %lu (absolute %lu)\n",
  208.               typelist.resource_type,typelist.reference_count+1,
  209.               typelist.resource_type,typelist.referencelist_offset,
  210.               resourceheader.map_offset+resourcemap.typelist_offset+
  211.               typelist.referencelist_offset);
  212.  
  213.   /* Loop thru the resources in numerical order */
  214.   for(i=0; i<=typelist.reference_count; i++)    {
  215.     fseek(fi,resourceheader.map_offset+resourcemap.typelist_offset+
  216.       typelist.referencelist_offset+i*sizeof(referencelist),0);
  217.     if(fread(&referencelist,1,sizeof(referencelist),fi)!=
  218.        sizeof(referencelist))
  219.       return(1);
  220.  
  221.     if(verbose) fprintf(stderr,
  222.             "resource_id = %u, attribute %02x\n",
  223.             referencelist.resource_id,
  224.             referencelist.reference.resource_attribute);
  225.  
  226.     referencelist.reference.resource_attribute=0;
  227.  
  228.     if(verbose) fprintf(stderr,
  229.             "data offset = %lu (absolute %lu)\n",
  230.             referencelist.reference.data_offset,
  231.             resourceheader.data_offset+
  232.             referencelist.reference.data_offset);
  233.  
  234.     if(read_resource(fi,resourceheader.data_offset+
  235.              referencelist.reference.data_offset,fo))
  236.       return(1);
  237.   }
  238.  
  239.   return(0);
  240. }
  241.  
  242.  
  243. /*
  244. ** Read resource data from given offset of file, decode Adobe coding
  245. */
  246. read_resource(FILE *fi,unsigned long offset,FILE *fo)    {
  247.   unsigned long size;
  248.   int c;
  249.  
  250.   fseek(fi,offset,0);
  251.   if(fread(&size,1,sizeof(size),fi)!=sizeof(size)) return(1);
  252.   if(!size) return(0);
  253.   if(verbose)
  254.     fprintf(stderr,"\tlength = %lu\n",size);
  255.  
  256.   c=fgetc(fi);
  257.  
  258.   /* This bit is a wart.  I really don't know why it's needed! */
  259.   /* Unfortunately, the results will be incorrect without it */
  260.   fgetc(fi); size--;
  261.  
  262.   switch(c)    {
  263.     /* Comment resource, just ignore */
  264.   case 0:
  265.     break;
  266.     /* ASCII text, copy directly to output */
  267.   case 1:
  268.     while(--size)
  269.       if((c=fgetc(fi))==-1)
  270.     return(1);
  271.       else if(c=='\r')
  272.     fputc('\n',fo);
  273.       else
  274.     fputc(c,fo);
  275.     break;
  276.     /* Binary data, convert to hexadecimal */
  277.   case 2:
  278.     for(c=1; --size; c++)
  279.       fprintf(fo,(c%32)?"%02X":"%02X\n",fgetc(fi));
  280.     fputc('\n',fo);
  281.     break;
  282.     /* End of file marker -- we actually should send ^D at this point? */
  283.   case 3:
  284.     break;
  285.     /* Font program is in data fork -- what the hell do we do to this? */
  286.     /* (we'll assume calling script has handled this bit) */
  287.   case 4:
  288.     fprintf(stderr,"Font program is in data fork\n");
  289.     /* Flow thru: Hit EOF -- a error */
  290.   case -1:
  291.   default:
  292.     return(1);
  293.     /* End-of-font marker resource */
  294.   case 5:
  295.     break;
  296.   }
  297.   return(0);
  298. }
  299.  
  300.  
  301. /*
  302. ** Read a PC pfb format file
  303. */
  304. pcfont(FILE *fi,FILE *fo)    {
  305.   int c;
  306.   unsigned long size;
  307.  
  308.   while((c=fgetc(fi))==128)    {
  309.     c=fgetc(fi);
  310.     size=fgetc(fi);
  311.     size+=fgetc(fi)<<(8);
  312.     size+=fgetc(fi)<<(8+8);
  313.     size+=fgetc(fi)<<(8+8+8);
  314.  
  315.     if(verbose) fprintf(stderr,"segment type = %u, length = %lu\n",c,size);
  316.     switch(c)    {
  317.       /* ASCII text, copy directly to output */
  318.     case 1:
  319.       while(size--)
  320.     if((c=fgetc(fi))==-1)
  321.       return(1);
  322.     else if(c=='\r')
  323.       fputc('\n',fo);
  324.     else
  325.       fputc(c,fo);
  326.       break;
  327.       /* Binary data, convert to hexadecimal */
  328.     case 2:
  329.       for(c=1; size--; c++)
  330.     fprintf(fo,(c%32)?"%02X":"%02X\n",fgetc(fi));
  331.       fputc('\n',fo);
  332.       break;
  333.       /* End of file marker or real EOF */
  334.     case 3:
  335.       return(0);
  336.       /* Hit EOF or anything else -- a error */
  337.     default:
  338.       return(1);
  339.     }
  340.   }
  341.  
  342.   if(verbose && c!=-1) fprintf(stderr,"read illegal byte = 0x%02x\n",c);
  343.   return(c!=-1);
  344. }
  345.